﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;

namespace Entitys.Models.Base
{
    public class ActionResult<T> : IActionResult<T>
    {
        protected ErrorResultBase? ErrorResult { get; set; }

        public bool Result { get; protected set; }
        public T? Content { get; protected set; }
        public List<string>? position { get; set; }

        public ActionResult(bool result, T content)
        {
            this.Result = result;
            this.Content = content;
            if (result)
                this.ErrorResult = new ErrorResult<ResultCommonCode>(ResultCommonCode.SUCCESS);
        }

        public ActionResult(ActionResult result)
        {
            this.Result = result.Result;
            this.ErrorResult = result.ErrorResult;
            this.Content = default;
        }

        public ActionResult ThrowErrorAction()
        {
            return new ActionResult(this.Result, this.ErrorResult);
        }

        public static ActionResult<T> OK(T content)
        {
            return new ActionResult<T>(true, content);
        }

        public override string ToString()
        {
            return ErrorResult?.ToString() ?? string.Empty;
        }

    }

    public class ActionResult
    : IActionResult<object>
    , IActionResult<bool>
    , IActionResult<byte>
    , IActionResult<sbyte>
    , IActionResult<char>
    , IActionResult<decimal>
    , IActionResult<double>
    , IActionResult<float>
    , IActionResult<int>
    , IActionResult<uint>
    , IActionResult<nint>
    , IActionResult<nuint>
    , IActionResult<long>
    , IActionResult<ulong>
    , IActionResult<short>
    , IActionResult<ushort>
    , IActionResult<Enum>
    , IActionResult<Guid>
    {

        public ErrorResultBase? ErrorResult { get; protected set; }

        public bool Result { get; protected set; }

        protected ActionResult()
        {

        }

        public ActionResult(bool result, ErrorResultBase? errorResult)
        {
            this.Result = result;
            this.ErrorResult = errorResult;
        }

        public static ActionResult Error<T>(T code, params string[] message)
            where T : Enum
        {
            return new ActionResult(false, new ErrorResult<T>(code, message));
        }

        public static IActionResult<T_Success> Success<T_Success>(T_Success content)
        {
            return new ActionResult<T_Success>(true, content);
        }

        public override string ToString()
        {
            return ErrorResult?.ToString() ?? string.Empty;
        }

        private static ActionResult instence_Success = new ActionResult { Result = true, ErrorResult = new ErrorResult<ResultCommonCode>(ResultCommonCode.SUCCESS) };
        internal static ActionResult Success()
        {
            return instence_Success;
        }

        public ActionResult ThrowErrorAction()
        {
            return this;
        }

    }

    public interface IActionResult
    {
        public bool Result { get; }

        public ActionResult ThrowErrorAction();
    }

    public interface IActionResult<in T> : IActionResult
    {

    }

    public class ErrorResultBase
    {
        public string[] message { get; protected set; } = new string[0];
    }

    public class ErrorResult<T> : ErrorResultBase
        where T : Enum
    {

        public T code { get; private set; }

        public ErrorResult(T code, string[] message)
        {
            this.code = code;
            this.message = message;
        }
        public ErrorResult(T code)
        {
            this.code = code;
            this.message = new string[0];
        }

        /// <summary>
        /// TODO:完善检查，避免出现循环递归错误
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        //private string TranslateDyn(dynamic code)
        //{
        //    return Translate(code);
        //}

        public string TranslateEnter(T code)
        {
            var resultTranslate = ActionResultExtension.GetResultTranslate<T>();
            if (resultTranslate == null)
            {
                return $"获取操作错误结果失败，没有继承实现{typeof(IResultTranslate<T>)}接口的类。";
            }
            return resultTranslate.Translate(code);
        }

        public override string ToString()
        {
            if (code == null)
                return base.ToString() ?? string.Empty;
            else
                return string.Format(this.TranslateEnter(code), message);
        }
    }

    public class ErrorResultResultCommonCode : IResultTranslate<ResultCommonCode>
    {
        public string Translate(ResultCommonCode code)
        {
            string part = string.Empty;
            switch (code)
            {
                case ResultCommonCode.SUCCESS:
                    part = "操作成功";
                    break;
                case ResultCommonCode.ThrowException:
                    part = "出现内部错误:[{0}]";
                    break;
                case ResultCommonCode.EntityNeedCarryObject:
                    part = "实体[{0}]需要实例[{1}]";
                    break;
                case ResultCommonCode.ParamError:
                    part = "参数[{0}:{1}]错误";
                    break;
                case ResultCommonCode.ResultContentError:
                    part = "期望[{0}]内容，实际返回了[{1}:{2}]结果";
                    break;
                case ResultCommonCode.UndefineError:
                    part = "发生未定义错误，[{0}]";
                    break;
                default:
                    part = code.ToString();
                    break;
            }
            return part;
        }
    }

    public interface IResultTranslate<T> where T : Enum
    {
        public abstract string Translate(T code);
    }

    public enum ResultCommonCode
    {
        SUCCESS,
        /// <summary>
        /// 需要1个message参数{0:Exception错误提示}
        /// </summary>
        ThrowException,
        /// <summary>
        /// 需要2个message参数{0:实体类型,1:实例类型}
        /// </summary>
        EntityNeedCarryObject,
        /// <summary>
        /// 需要2个message参数{0:参数名称,1:参数值}
        /// </summary>
        ParamError,
        /// <summary>
        /// 需要3个message参数{0:期望的结果Content类型,1:返回的结果类型,2:返回的结果Content类型}
        /// </summary>
        ResultContentError,
        /// <summary>
        /// 需要1个message参数
        /// <para>0:错误描述</para>
        /// </summary>
        UndefineError,
    }


    public class ActionResultErrorResultException : Exception
    {
        private IActionResult JKErrorResult { get; set; }

        public override string Message => $"{JKErrorResult}-{base.Message}";

        public ActionResultErrorResultException(IActionResult jKErrorResult)
        {
            this.JKErrorResult = jKErrorResult;
        }

        public override string ToString()
        {
            return $"{JKErrorResult}-{base.ToString()}";
        }
    }

    public static class ActionResultExtension
    {
        private static readonly Dictionary<Type, object> _Type_Translate = new Dictionary<Type, object>();

        static ActionResultExtension()
        {
            TypeInfo[] type_ResultTran =
                AppDomain.CurrentDomain.GetAssemblies()
                .Where((Assembly a) => !a.IsDynamic)
                .SelectMany((Assembly a) => a.DefinedTypes)
                .Where(p => !p.IsAbstract
                    && p.ImplementedInterfaces.FirstOrDefault(imp => imp.IsGenericType && imp.GetGenericTypeDefinition() == typeof(IResultTranslate<>)) != null)
                .ToArray();
            foreach (var t in type_ResultTran)
            {
                var t_instance = Activator.CreateInstance(t);
                foreach (var impType in t.ImplementedInterfaces.Where(imp => imp.IsGenericType && imp.GetGenericTypeDefinition() == typeof(IResultTranslate<>)))
                {
                    _Type_Translate.TryAdd(impType, t_instance);
                }
            }
        }
        private static IResultTranslate<T> TryGetResultTranslate<T>()
            where T : Enum
        {
            IResultTranslate<T> resultTranslate = null;
            TypeInfo[] type_ResultTran =
                typeof(T).Assembly.DefinedTypes
                .Where(p => !p.IsAbstract
                    && p.ImplementedInterfaces.FirstOrDefault(imp => imp.IsGenericType && imp.GetGenericTypeDefinition() == typeof(IResultTranslate<>)) != null)
                .ToArray();

            foreach (var t in type_ResultTran)
            {
                var t_instance = Activator.CreateInstance(t);
                foreach (var impType in t.ImplementedInterfaces.Where(imp => imp.IsGenericType && imp.GetGenericTypeDefinition() == typeof(IResultTranslate<>)))
                {
                    if (impType == typeof(IResultTranslate<T>))
                        resultTranslate = t_instance as IResultTranslate<T>;
                    _Type_Translate.TryAdd(impType, t_instance);
                }
            }

            return resultTranslate;
        }
        public static IResultTranslate<T> GetResultTranslate<T>()
            where T : Enum
        {
            if (_Type_Translate.TryGetValue(typeof(IResultTranslate<T>), out object tranlate))
                return tranlate as IResultTranslate<T>;
            else
                return TryGetResultTranslate<T>();

        }

        public static T? GetContent<T>(this IActionResult<T> action)
        {
            return action != null && action is ActionResult<T>
                ? (action as ActionResult<T>).Content
                : default(T);
        }

        public static ActionResult GetResult<T>(this T code, params string[] strings_param)
            where T : Enum
        {
            return ActionResult.Error(code, strings_param);
        }

        public static IActionResult<T> ThrowPosition<T>(this IActionResult<T> resultAction, [CallerMemberName] string caller = "")
        {
            //TODO:
            return resultAction;
        }
        public static ActionResult ThrowPosition(this ActionResult resultAction, [CallerMemberName] string caller = "")
        {
            return resultAction;
        }
        public static IActionResult ThrowPosition(this IActionResult resultAction, [CallerMemberName] string caller = "")
        {
            return resultAction;
        }
    }

}